#include<bits/stdc++.h> 
using namespace std;
//	Eva希望自己的色彩条与众不同，他只想从不想要的色彩条里裁剪出自己喜欢的颜色，按照顺序再
//	拼合起来，组成自己的色彩条。一个人的眼睛能够分辨200种以下的不同色彩，所以Eva喜欢的颜
//	色也是有限的。但是原始色彩条可以很长，并且Eva希望自己喜欢的条子可以达到最长，所以我们
//	要帮忙得到最佳结果。需要注意的是，解决方案可能不唯一，但是我们只需要告诉他最长的长度
//	就行。例如，给定一组色彩条{2 2 4 1 5 5 6 3 1 1 5 6}，假设Eva喜欢的颜色以及顺序的{2 3 
//	1 5 6}，然后就有四个最好的结果为{2 2 1 1 1 5 6}{2 2 1 5 5 5 6}{2 2 1 5 5 6 6}{2 2 3 1
//	1 5 6}
//1.每个输入有一个测试用例，每个用例第一行为N≤200，表示总共存在的色彩数量，编号1~N。
//2.第二行开始一个正整数M≤200，然后有序地跟着M个Eva喜欢的颜色
//3.最后开始一个正整数L≤10000，表示现有色彩条的长度，然后跟着L个色彩情况
//4.对于每一个测试用例，需要侧输出Eva最喜欢的色彩条的最大长度 
//5.动态规划，问题转化
//这道题其实整体思路可以转换为如下，以题目样例为例子：
// 2 2 4 1 5 5 6 3 1 1 5 6 以及 2 3 1 5 6
//我们先把前者里所有在后者中存在的数据都找到，原封不动地按照其在前者中的顺序并压入向量
//，得到2 2 1 5 5 6 3 1 1 5 6，然后我们称新的这个向量为有效数组，我们需要在有效数组中
//寻找到与Eva所喜欢的序列一致顺序的结果，所以我们以后者为桶，分别找到每个桶在有效数组中 
//存在的所有位置，得到2{1 2}，3{7}，1{3 8 9}，5{4 5 10}，6{6 11}。我们得到了这一系列数
//据后其实就可以发现，我们只需要把1 2 7 3 8 9 4 5 10 6 11这一个序列拿出来，假如我们此刻
//选择了有效数组中的3，也就是第7位，那么第7位以前的数据就不可选择，只能继续找7位以后的
//数字，也就是说1 2 7 3 8 9 4 5 10 6 11这串中1所包含的3 8 9只能找8和9，如果1找了8，9也
//可以找，而5只能接着找10，6只能接着找11。从而形成一个递增的子序列，所以我找到其中最长
//递增子序列就行，且这个子序列可以不连续。所以问题最终就转化为了如何求一串数字中可不连
//续的递增子序列的最长长度。 
int main(){
	int N,M,L;
	cin>>N;	//没有用到 
	vector<int> color_fav;	//有效数组 
	cin>>M;
	vector<int> eva_color(M);	//直接开个M大小的向量即可，因为大小已知。用于存储Eva喜欢的颜色 
	vector<int> color_pos[M];	//开M个数组，用于桶处理 
	unordered_map<int, int> vec_pos;	//数字对应的桶下标映射 
	for(int i = 0;i<M;i++){
		int tmp;
		cin>>tmp;
		eva_color.push_back(tmp);	//读入Eva喜欢的颜色 
		vec_pos[tmp] = i;	//建立桶映射 
	}
	cin>>L;
	for(int i =0;i<L;i++){
		int tmp;
		cin>>tmp;	//读入色彩条情况 
		if(find(eva_color.begin(), eva_color.end(), tmp)!=eva_color.end()){	//如果这个颜色是Eva中意的，就推入有效数组中 
			color_fav.push_back(tmp);
		}
	}
	int len = color_fav.size();	//得到有效数组的长度 
	if(len<=1)	//如果长度≤1，就直接输出返回，也不用处理了 
	{
		cout<<len<<endl;
		return 0;
	}
	for(unsigned int i = 0;i<len;i++){	//把有效数组中的数据下标丢到桶里取 
		color_pos[vec_pos[color_fav[i]]].push_back(i);
	}
	int final_pos[len];	//最后转换成的用于找递增子序列的下标序列 
	int maxLen[len];	//用于以某个结点为终点的最大递增子序列的长度 
	fill(maxLen,maxLen+len,1);	//全部填充1，自己到自己也是一个长度 
	int count_ = 0;	//用于将桶中的下标全部拿出来放到final_pos中，形成下标序列 
	for(unsigned int i = 0;i<M;i++){
		for(unsigned int j = 0;j<color_pos[i].size();j++){
			final_pos[count_] = color_pos[i][j];
			count_++;
		}
	}
	for(int i = 1;i<len;i++){	//动态规划部分 
		for(int j = 0;j<i;j++){	//从0到i的前一位为止 
			if(final_pos[j]<final_pos[i]){	//如果j这个位置的下标数据比i的小，则说明是递增情况 
				maxLen[i] = max(maxLen[i], maxLen[j] + 1);	//i这边就对比目前的最长长度和到j位置的最长长度+1比哪个长 
			}
		} 
	}
	int max_ = 0;
	for(int i = 0;i<len;i++){	//遍历，输出整个长度结果中的最长长度 
		if(maxLen[i]>max_){
			max_ = maxLen[i];
		}
	}
	cout<<max_<<endl;
	return 0;
} 